package ltd.dujiabao.orderservice.listener;

import lombok.extern.slf4j.Slf4j;
import ltd.dujiabao.common.event.BillingFailedEvent;
import ltd.dujiabao.common.event.InventoryDeductedEvent;
import ltd.dujiabao.common.event.InventoryFailedEvent;
import ltd.dujiabao.orderservice.dao.OrderRepository;
import ltd.dujiabao.orderservice.domain.enums.OrderStatus;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;


/**
 * @author Bowie Du
 * @date 2025/7/13 19:51
 */
@Slf4j
@Component
public class OrderListener {
    @Autowired
    private OrderRepository orderRepository;

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(
                            value = "order.inventory.fail.queue",
                            durable = "true"
                    ),
                    exchange = @Exchange(
                            value = "inventory.fail.exchange",
                            durable = "true",
                            type = ExchangeTypes.FANOUT
                    )
            )
    )
    @Transactional(rollbackFor = Exception.class)
    public void handleInventoryFailEvent(InventoryFailedEvent event) {
        rollback(event.getOrderId());
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(
                            value = "order.billing.fail.queue",
                            durable = "true"
                    ),
                    exchange = @Exchange(
                            value = "billing.fail.exchange",
                            durable = "true",
                            type = ExchangeTypes.FANOUT
                    )
            )
    )
    @Transactional(rollbackFor = Exception.class)
    public void handleBillingFailedEvent(BillingFailedEvent event) {
        rollback(event.getOrderId());
    }

    @Transactional(rollbackFor = Exception.class)
    public void rollback(Long orderId) {
        int effected = orderRepository.updateStatusById(orderId, OrderStatus.FAILED.name());
        log.info("update orderId {} status as {}, isSuccess {}",
                orderId, OrderStatus.FAILED.name(), effected > 0);
    }


    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(
                            value = "order.inventory.success.queue",
                            durable = "true"
                    ),
                    exchange = @Exchange(
                            value = "inventory.success.exchange",
                            durable = "true",
                            type = ExchangeTypes.FANOUT
                    )
            )
    )
    @Transactional(rollbackFor = Exception.class)
    public void handleInventorySuccessEvent(InventoryDeductedEvent event) {
        int effected = orderRepository.compareAndSetStatusById(
                event.getOrderId(),
                Collections.singletonList(OrderStatus.ORDER_CREATED.name()),
                OrderStatus.STOCK_DEDUCTED.name());
        log.info("update orderId {} status as {}, isSuccess {}",
                event.getOrderId(), OrderStatus.STOCK_DEDUCTED.name(), effected > 0);
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(
                            value = "order.billing.success.queue",
                            durable = "true"
                    ),
                    exchange = @Exchange(
                            value = "billing.success.exchange",
                            durable = "true",
                            type = ExchangeTypes.FANOUT
                    )
            )
    )
    @Transactional(rollbackFor = Exception.class)
    public void handleBillingSuccessEvent(InventoryDeductedEvent event) {
        int effected = orderRepository.compareAndSetStatusById(
                event.getOrderId(),
                List.of(OrderStatus.ORDER_CREATED.name(), OrderStatus.STOCK_DEDUCTED.name()),
                OrderStatus.BALANCED.name());
        log.info("update orderId {} status as {}, isSuccess {}",
                event.getOrderId(), OrderStatus.BALANCED.name(), effected > 0);
    }
}
